
/* Generated by Interface Builder */

#import "SpectrumView.h"
#import <appkit/appkit.h>
#import <appkit/PrintInfo.h>

float back_ground = 0.0/3.0, draw_gray = 3.0/3.0, marker_gray = 1.0/3.0;
float freq_range,amp_range,*last_data;
float lastVertPos,lastHorPos;
int last_length;
BOOL not_first_time;
NXPoint  last_cursor;

@implementation SpectrumView

- setBackGround: (float) gray
{
    back_ground = gray;
    return self;
}

- setDraw: (float) gray
{
    draw_gray = gray;
    return self;
}

- setFreqRange: (float) aFreqRange andAmpRange: (float) anAmpRange
{
    freq_range = aFreqRange;
    amp_range = anAmpRange;
    return self;
}

- (float) ampRange
{
    return amp_range;
}

- drawSpectrum: (int) length array: (float *) f
{
    [self drawSpectrum: length array: f erase: FALSE];
    return self;
}

- drawSpectrum: (int) length array: (float *) f erase: (BOOL) erase
{
    int i,incr;
    double xstep,ymax,max=0.0;
    xstep = frame.size.width / length;
    ymax = frame.size.height;
    incr = length / frame.size.width;
    if (last_length!=length) {
        if (last_data) free(last_data);
	last_data = (float *) malloc(4 * length);
	last_length = length;
    }
    [self lockFocus];
    [self setOpaque: TRUE];
    PSsetlinewidth(0.1);
    if (erase)
        PSsetgray(back_ground);
    else
        PSsetgray(draw_gray);
    PSmoveto(0.0,f[0] * ymax);
    last_data[0] = f[0];
    for (i=1;i<length;i++) {
	last_data[i] = f[i];
	if (f[i]>max) max = f[i];
	if (incr==0)	{
	    PSlineto((double) i * xstep,max * ymax);
	    max = 0.0;	
	}
	else if ((i%incr)==0)	{
	    PSlineto((double) i * xstep,max * ymax);
	    max = 0.0;
	}
    }
    PSstroke();
    PSflushgraphics();
    [self unlockFocus];
     [[self window] flushWindow];
    last_cursor.x = -1.0;
    return self;
}

- placeVerticals: (float) positions;
{
    double xpos,ypos,xdel;
    xpos = frame.size.width * positions;
    xdel = xpos;
    lastVertPos = positions;
    if (xdel<=0) xdel = 1.0;
    ypos = frame.size.height;
    [self lockFocus];
    [self setOpaque: TRUE];
    PSsetlinewidth(0.1);
    PSsetgray(marker_gray);
    while (xpos<=frame.size.width)	{
        PSmoveto(xpos,0.0);
        PSlineto(xpos,ypos);
	xpos += xdel;
    }
    PSstroke();
    PSflushgraphics();
    [self unlockFocus];
    return self;
}

- placeHorizontals: (float) heights;
{
    double xpos,ypos,ydel;
    xpos = frame.size.width;
    ypos = frame.size.height * heights;
    ydel = ypos;
    lastHorPos = heights;
    if (ydel<=0) ydel = 1.0;
    [self lockFocus];
    [self setOpaque: TRUE];
    PSsetlinewidth(0.1);
    PSsetgray(marker_gray);
    while (ypos<frame.size.height)	{
        PSmoveto(0.0,ypos);
        PSlineto(xpos,ypos);
	ypos += ydel;
    }
    PSstroke();
    PSflushgraphics();
    [self unlockFocus];
    return self;

}
    
- clear
{
    [self lockFocus];
    [self setOpaque: TRUE];
    PSsetgray(back_ground);
    PSrectfill(0.,0.,bounds.size.width,bounds.size.height);
    PSstroke();
    PSflushgraphics();
    [self unlockFocus];
    return self;
}

- drawSelf: (NXRect *) r : (int) n 
{
    if (not_first_time)   {
        [self clear];
	[self drawSpectrum: last_length array: last_data erase: FALSE];
	[self placeHorizontals: lastHorPos];
	[self placeVerticals: lastVertPos];
	if (last_cursor.x>0 && last_cursor.x<frame.size.width) [self drawCursor: last_cursor erase: FALSE];
    }
    else	{
       [self clear];
	not_first_time = TRUE;
    }
    
return self;
}

#define MOVE_MASK NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK

- (BOOL)acceptsFirstMouse
{
  return (YES);
}

- mouseDown: (NXEvent *)event
{
    NXPoint currentPosition;
    NXEvent *nextEvent;
    BOOL tracking = TRUE;
    int oldMask,checkMask;
    
    oldMask = [window eventMask];
    checkMask = NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK;
    [window setEventMask: (oldMask | checkMask)];
    
    [self lockFocus];
    
    currentPosition = event->location;
    [self convertPoint:&currentPosition fromView:nil];
    event = [NXApp getNextEvent:MOVE_MASK];

    if (last_cursor.x>0 && last_cursor.x<frame.size.width) 
    [self drawCursor: last_cursor erase: TRUE];
//    if (event->type!=NX_MOUSEUPMASK && last_data)    {
	while (tracking) {
	    nextEvent = [NXApp getNextEvent: checkMask];
	    tracking = (nextEvent->type != NX_MOUSEUP);
	    if (tracking)	{
	        currentPosition = nextEvent -> location;
		[self convertPoint:&currentPosition fromView:nil];
	        if (currentPosition.x>0.0 && currentPosition.x < frame.size.width 
	    		&& currentPosition.y > 0.0 && currentPosition.y < frame.size.height)    {
		    if (last_cursor.x != currentPosition.x)	{
		        [self drawCursor: last_cursor erase: TRUE];
		        [self drawCursor: currentPosition erase: FALSE];
			last_cursor = currentPosition;
			[window flushWindow];
		    }
	        }
	    }
	}
//    }
   [self unlockFocus];
    [window setEventMask:oldMask];
    return self;
}

- drawCursor: (NXPoint) point erase: (BOOL) erase
{
    double xpos,ypos1,ypos2,ypos3,min,max;
    int data_position;
    data_position = point.x  / frame.size.width * last_length + 0.5;
    xpos = point.x;
    min = frame.size.height;
    max = 0.0;
    ypos1 = frame.size.height * last_data[data_position - 1];
    ypos2 = frame.size.height * last_data[data_position];
    ypos3 = frame.size.height * last_data[data_position + 1];
    if (ypos1>max) max = ypos1;
    if (ypos2>max) max = ypos2;
    if (ypos3>max) max = ypos3;
    if (ypos1<min) min = ypos1;
    if (ypos2<min) min = ypos2;
    if (ypos3<min) min = ypos3;
    [self lockFocus];
    [self setOpaque: TRUE];
    PSsetlinewidth(0.1);
    if (erase)
        PSsetgray(back_ground);
    else	{
        PSsetgray(marker_gray);
	[ampField setFloatValue: amp_range * (float) (1.0 - ypos2 / frame.size.height)];
	[freqField setFloatValue: freq_range * (float) (xpos / frame.size.width)];
    }
    if (xpos==frame.size.width) xpos -= 1.0;
    PSmoveto(xpos,0.0);
    PSlineto(xpos,min - 5.0);
    PSmoveto(xpos,max + 5.0);
    PSlineto(xpos,frame.size.height);
    PSstroke();
    PSflushgraphics();
    [self unlockFocus];
    return self;
}

- printMyPSCode:sender
{
    [[[[[NXApp printInfo] setOrientation:NX_LANDSCAPE andAdjust:YES]
	    setHorizCentered:YES]
		    setVertCentered:YES]
			    setMarginLeft:0.0
			    right:0.0
			    top:0.0
			    bottom:0.0];
    
    if (back_ground == 0.0/3.0)	{
	NXRunAlertPanel("Too much black ink for the printer.",
	"I'm going to reverse my colors,\
	 From now on this view will show reverse.",NULL,NULL,"OK"); 
          back_ground = 3.0/3.0;
	  draw_gray = 0.0/3.0;
	  marker_gray = 2.0/3.0 ;
           [self clear];
	  [self drawSpectrum: last_length array: last_data erase: FALSE];
	  [self placeHorizontals: lastHorPos];
	  [self placeVerticals: lastVertPos];
	  if (last_cursor.x>0 && last_cursor.x<frame.size.width) [self drawCursor: last_cursor erase: FALSE];
    }
    [[self window] printPSCode: sender];	
    return self;      
}

@end
